﻿using System;
using System.Linq;
using System.Collections.Generic;
using AutoMapper;
using GroceryList.Domain.Model.GroceryList;
using GroceryList.Domain.Model.Product;
using GroceryList.Domain.Repositories;
using GroceryList.Front.Web.ViewModels;

namespace GroceryList.Front.Web.Service
{
    public class ListaCompraService: IListaCompraService
    {
        private IListaCompraRepository _listaCompraRepository;
        private IMappingEngine _automapper;
        private IProductoRepository _productoRepository;

        public ListaCompraService(IListaCompraRepository listaCompraRepository,IMappingEngine automapper,IProductoRepository productoRepository)
        {
            _listaCompraRepository = listaCompraRepository;
            _productoRepository = productoRepository;
            _automapper = automapper;
        }

        public ListaCompraDto GuardarLista(ListaCompraDto lista)
        {
            ListaCompra listaCompra;
            if (lista.Codigo != null)
            {
                listaCompra = _listaCompraRepository.Single((Guid)lista.Codigo);
                listaCompra.Nombre = lista.Nombre;
                listaCompra.Fecha = lista.Fecha;
            }
            else
                listaCompra = new ListaCompra(lista.Nombre, lista.Fecha);

            var aux = listaCompra.DetalleProducto.Where(detalleProducto => detalleProducto.Cantidad == 0).ToArray();
            foreach (var detalleProducto in aux)
            {
                listaCompra.BorrarDetalle(detalleProducto);
                _listaCompraRepository.BorrarDetalles(detalleProducto);
            }

            //var aux2 = listaCompra.DetalleProducto.ToArray();
            //foreach (var detalleProducto in aux2)
            //{
            //    if(lista.DetalleProducto.Select(dp => Producto.Desde(dp.Producto)).Contains(detalleProducto.Producto)==false)
            //    {
            //        listaCompra.BorrarDetalle(detalleProducto);
            //        _listaCompraRepository.BorrarDetalles(detalleProducto);
            //    }
   
            //}

            foreach (var detalleProducto in aux)
            {
                listaCompra.BorrarDetalle(detalleProducto);
                _listaCompraRepository.BorrarDetalles(detalleProducto);
            }
            

            if (lista.DetalleProducto != null)
            {
                foreach (var detalle in lista.DetalleProducto)
                {
                    if (detalle.Cantidad > 0)
                    {
                        var producto = _productoRepository.Single(Producto.Desde(detalle.Producto));
                        if (producto == null)
                            throw new ArgumentException(String.Format("El producto con nombre '{0}' no existe",detalle.Producto));
                        listaCompra.AnhadirDetalle(producto,detalle.Cantidad,detalle.Observaciones);
                    }

                }
            }
            _listaCompraRepository.Save(listaCompra);


            return _automapper.Map<ListaCompra, ListaCompraDto>(listaCompra);
        }

        public void Eliminar(Guid codigoLista)
        {
            var lista = _listaCompraRepository.Single(codigoLista);
            _listaCompraRepository.Delete(lista);
        }

        public ProductoDto ObtenerProducto(string nombre)
        {
            var producto = _productoRepository.Single(Producto.Desde(nombre));
            return _automapper.Map<Producto, ProductoDto>(producto);
        }

        public IEnumerable<ProductoDto> ObtenerProductos()
        {
            var productos = _productoRepository.All();
            return _automapper.Map<IEnumerable<Producto>, IEnumerable<ProductoDto>>(productos);
        }

        public ListaCompraDto ObtenerListaModoCompra(Guid codigoLista)
        {
            var listaCompra = _listaCompraRepository.Single((Guid)codigoLista);

            var listaCompraDto = _automapper.Map<ListaCompra, ListaCompraDto>(listaCompra);
            listaCompraDto.DetalleProducto = _automapper.Map<IEnumerable<DetalleProducto>,IEnumerable<DetalleDto>>(listaCompra.DetallesModoCompra);


            return listaCompraDto;
        }

        public void ComprarProductoDeLaLista(Guid codigo,string nombreProducto)
        {
            var listaCompra = _listaCompraRepository.Single(codigo);

            //Supongo que esta consulta se puede mejorar (por ejemplo para que 
            //en vez de acceder al nombre se busque el producto... como tal)...pero 
            //es que creo que, con el tiempo, el modelo de los detalleSSSS cambie
            // teniendo únicamente el nombre del producto como relación con producto
            var detalleAComprar =
                listaCompra.DetalleProducto.
                    Where(dp => dp.Producto.Nombre == nombreProducto).Single();
            detalleAComprar.Estado = EstadoDelDetalle.Desde(EstadoDetalle.Comprado);
            
            _listaCompraRepository.Save(listaCompra);
        }

        public IEnumerable<ListaCompraSimpleDto> ObtenerTodas()
        {
            var listas = _listaCompraRepository.All();
            return _automapper.Map<IEnumerable<ListaCompra>, IEnumerable<ListaCompraSimpleDto>>(listas);
        }

        public void TacharProductoDeLaLista(Guid codigo, string nombreProducto)
        {
            var listaCompra = _listaCompraRepository.Single(codigo);

            //Supongo que esta consulta se puede mejorar (por ejemplo para que 
            //en vez de acceder al nombre se busque el producto... como tal)...pero 
            //es que creo que, con el tiempo, el modelo de los detalleSSSS cambie
            // teniendo únicamente el nombre del producto como relación con producto
            var detalleAComprar =
                listaCompra.DetalleProducto.
                    Where(dp => dp.Producto.Nombre == nombreProducto).Single();
            detalleAComprar.Estado = EstadoDelDetalle.Desde(EstadoDetalle.Tachado);

            _listaCompraRepository.Save(listaCompra);
            
        }

        public ListaCompraDto ObtenerLista(Guid? codigoLista, string terminoDeBusqueda = null)
        {
            var listaCompraDto = new ListaCompraDto();
            if (codigoLista != null)
            {
                var listaCompra = _listaCompraRepository.Single((Guid)codigoLista);
                listaCompraDto = _automapper.Map<ListaCompra, ListaCompraDto>(listaCompra);
            }

            List<DetalleDto> detalles;
            IEnumerable<ProductoDto> productos;
            if (string.IsNullOrEmpty(terminoDeBusqueda))
            {
                detalles = listaCompraDto.DetalleProducto.ToList();
                productos = ObtenerProductos();
            }
            else
            {
                detalles = listaCompraDto.DetalleProducto.Where(dp => dp.Producto.ToLower().Contains(terminoDeBusqueda.ToLower())).ToList();
                productos = ObtenerProductos().Where(pr=>pr.Nombre.ToLower().Contains(terminoDeBusqueda));
            }

            detalles.AddRange(from productoDto in productos
                              where !listaCompraDto.DetalleProducto.Select(dp => dp.Producto).Contains(productoDto.Nombre) 
                              select new DetalleDto { Cantidad = 0, Observaciones = "", Producto = productoDto.Nombre });

            listaCompraDto.DetalleProducto = detalles;

            return listaCompraDto;
           
        }
    }
}